package com.ljt.springdataredisdemo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.concurrent.TimeUnit;

@SpringBootTest
public class HotSpotInvalidWithLock {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void hotSpotInvalidWithLock() {
        // 查询一个热点数据
        String name = stringRedisTemplate.opsForValue().get("name");
        System.out.println(Thread.currentThread().getName()+"查询数据："+ name);
        // 热点数据缓存没有了，需要查数据库去建立缓存在返回，要用锁来保证一个人来建立缓存。没有拿到锁应该一直等待并重试，建立缓存我这里猜应该就3秒吧
        if (name == null) {
            synchronized (HotSpotInvalidWithLock.class) {
                // 拿到锁了别忘了，检查一下缓存有没有建立了，建立了就不需要重新建立缓存了
                name = stringRedisTemplate.opsForValue().get("name");
                if (name != null) {
                    System.out.println("返回：" + name);
                    return;
                }
                // 这里查数据库了，值为ljt
                // TODO 为了健壮性，可以判断值是不是空，空也建立空缓存，但是要日志记录一下，因为这个可是热点数据诶。
                name = "ljt";
                stringRedisTemplate.opsForValue().set("name", name, 20, TimeUnit.SECONDS);
                System.out.println(Thread.currentThread()+"建立缓存，然后返回："+name);
                return;
            }
        }
        System.out.println("返回：" + name);
    }

    @Test
    public void mockManyThreads() throws InterruptedException {
        for (int i = 0; i < 3000; i++) {
            new Thread(() -> hotSpotInvalidWithLock()).start();
        }
        // 防止主线程先关闭,好像主线程关闭了,他这个redisConnection就会立即断开了,所以这里加个sleep
        Thread.sleep(1000*5);
    }
}
